package recorder

import (
	"fmt"
	"time"

	"github.com/bluenviron/mediacommon/v2/pkg/formats/mpegts"
)

type formatMPEGTSTrack struct {
	f     *formatMPEGTS
	codec mpegts.Codec

	track            *mpegts.Track
	startInitialized bool
	startDTS         time.Duration
	startNTP         time.Time
}

func (t *formatMPEGTSTrack) initialize() {
	t.track = &mpegts.Track{
		Codec: t.codec,
	}
}

func (t *formatMPEGTSTrack) write(
	dts time.Duration,
	ntp time.Time,
	randomAccess bool,
	cb func(track *mpegts.Track) error,
) error {
	isVideo := t.track.Codec.IsVideo()

	if isVideo {
		t.f.hasVideo = true
	}

	if !t.startInitialized {
		t.startDTS = dts
		t.startNTP = ntp
		t.startInitialized = true
	} else {
		drift := ntp.Sub(t.startNTP) - (dts - t.startDTS)
		if drift < -ntpDriftTolerance || drift > ntpDriftTolerance {
			return fmt.Errorf("detected drift between recording duration and absolute time, resetting")
		}
	}

	switch {
	case t.f.currentSegment == nil:
		t.f.currentSegment = &formatMPEGTSSegment{
			pathFormat2:       t.f.ri.pathFormat2,
			flush:             t.f.bw.Flush,
			onSegmentCreate:   t.f.ri.onSegmentCreate,
			onSegmentComplete: t.f.ri.onSegmentComplete,
			startDTS:          dts,
			startNTP:          ntp,
			log:               t.f.ri,
		}
		t.f.currentSegment.initialize()
		t.f.dw.setTarget(t.f.currentSegment)

	case (!t.f.hasVideo || isVideo) &&
		randomAccess &&
		(dts-t.f.currentSegment.startDTS) >= t.f.ri.segmentDuration:
		t.f.currentSegment.lastDTS = dts
		err := t.f.currentSegment.close()
		if err != nil {
			return err
		}

		t.f.currentSegment = &formatMPEGTSSegment{
			pathFormat2:       t.f.ri.pathFormat2,
			flush:             t.f.bw.Flush,
			onSegmentCreate:   t.f.ri.onSegmentCreate,
			onSegmentComplete: t.f.ri.onSegmentComplete,
			startDTS:          dts,
			startNTP:          ntp,
			log:               t.f.ri,
		}
		t.f.currentSegment.initialize()
		t.f.dw.setTarget(t.f.currentSegment)

	case (dts - t.f.currentSegment.lastFlush) >= t.f.ri.partDuration:
		err := t.f.bw.Flush()
		if err != nil {
			return err
		}

		t.f.currentSegment.lastFlush = dts
	}

	t.f.currentSegment.lastDTS = dts

	return cb(t.track)
}
